package com.project.common.fundamental.controller;

import com.project.common.fundamental.response.body.LocationBody;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;

import java.io.Serializable;
import java.net.URI;
import java.nio.charset.StandardCharsets;

@SuppressWarnings("unused")
public interface RestfulController {

    /**
     * 数据响应 HTTP STATUS = 200 OK
     */
    default <B> ResponseEntity<B> ok(B body) {
        return ResponseEntity.ok(body);
    }

    /**
     * 操作响应 HTTP STATUS = 201 CREATED
     */
    default <K extends Serializable> ResponseEntity<LocationBody> created(K key) {
        return created(getLocation(key));
    }

    /**
     * 操作响应 HTTP STATUS = 201 CREATED
     */
    default ResponseEntity<LocationBody> created(String location) {
        return created(location, new LocationBody(location));
    }

    /**
     * 操作响应 HTTP STATUS = 201 CREATED
     */
    default ResponseEntity<LocationBody> created(URI location) {
        return created(location, new LocationBody(location));
    }

    /**
     * 操作响应 HTTP STATUS = 201 CREATED
     */
    default <B> ResponseEntity<B> created(String uri, B body) {
        return created(URI.create(uri), body);
    }

    /**
     * 操作响应 HTTP STATUS = 201 CREATED
     */
    default <B> ResponseEntity<B> created(URI location, B body) {
        return ResponseEntity.created(location).body(body);
    }

    /**
     * 操作响应 HTTP STATUS = 202 ACCEPTED
     */
    default ResponseEntity<Void> accepted() {
        return ResponseEntity.accepted().build();
    }

    /**
     * 操作响应 HTTP STATUS = 202 ACCEPTED
     */
    default ResponseEntity<LocationBody> accepted(String location) {
        return accepted(location, new LocationBody(location));
    }

    /**
     * 操作响应 HTTP STATUS = 202 ACCEPTED
     */
    default ResponseEntity<LocationBody> accepted(URI location) {
        return accepted(location, new LocationBody(location));
    }

    /**
     * 操作响应 HTTP STATUS = 202 ACCEPTED
     */
    default <B> ResponseEntity<B> accepted(String location, B body) {
        return ResponseEntity.accepted()
            .header("Location", location)
            .body(body);
    }

    /**
     * 操作响应 HTTP STATUS = 202 ACCEPTED
     */
    default <B> ResponseEntity<B> accepted(URI location, B body) {
        return ResponseEntity.accepted()
            .header("Location", location.toString())
            .body(body);
    }

    /**
     * HTTP STATUS  = 204 NO CONTENT
     */
    default ResponseEntity<?> noContent() {
        return ResponseEntity.noContent().build();
    }

    /**
     * HTTP STATUS = 404 NOT FOUND
     */
    default ResponseEntity<?> notFound() {
        return ResponseEntity.notFound().build();
    }

    /**
     * HTTP STATUS = 500 server internel error
     */
    default <B> ResponseEntity<B> fail(B body) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(body);
    }

    /**
     * 下载文件
     */
    default ResponseEntity<byte[]> download(byte[] buffer, String fileName) {
        HttpHeaders headers = new HttpHeaders();
        //设置下载的附件 (fileName必须处理中文名称!)
        headers.setContentDispositionFormData("attachment",
            new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));
        //设置MIME类型
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        return new ResponseEntity<>(buffer, headers, HttpStatus.ACCEPTED);
    }

    default <K extends Serializable> String getLocation(K key) {
        Class<? extends RestfulController> controller = this.getClass();
        RequestMapping requestMapping = controller.getAnnotation(RequestMapping.class);
        if (requestMapping != null) {
            String[] mappings = requestMapping.value();
            if (mappings.length > 0) {
                return String.join(mappings[0], String.valueOf(key));
            }
        }
        return "";
    }
}
